import 'package:dio/dio.dart';
import 'package:flutter_house_manager/utils/Emitter.dart';
import 'package:flutter_house_manager/utils/PromptAction.dart';
import 'package:flutter_house_manager/utils/TokenManager.dart';

import '../constants/index.dart';

class DioRequest {
  final _dio = Dio(); // 它相当于const instance = axios.create()

// 构造函数 在new这个类的时候执行
  DioRequest() {
    // _dio.options.baseUrl = GlobalVariable.BASE_URL;
    // // 连接超时时间
    // _dio.options.connectTimeout =
    //     const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT);
    // // 接收超时时间
    // _dio.options.receiveTimeout =
    //     const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT);
    // 这叫链式调用
    _dio
      ..options.baseUrl = GlobalVariable.BASE_URL
      ..options.connectTimeout =
          const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT)
      ..options.receiveTimeout =
          const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT)
      ..options.sendTimeout =
          const Duration(seconds: GlobalVariable.NEW_WORK_TIME_OUT);

    _dio.interceptors.add(InterceptorsWrapper(onRequest: (context, handler) {
      // 请求拦截器
      // 注入token
      String token = tokenManager.getToken();
      if (token.isNotEmpty) {
        context.headers["Authorization"] = 'Bearer $token';
      }

      handler.next(context);
    }, onResponse: (context, handler) {
      // 2xx才是成功
      //http状态码
      if (context.statusCode! >= 200 && context.statusCode! < 300) {
        // 响应拦截器
        handler.next(context); // 成功
      } else {
        PromptAction.showError("请求错误");
        // 说明 Promise pending fullfiled rejected
        handler
            .reject(DioException(requestOptions: context.requestOptions)); // 失败
      }
    },
        // 错误拦截器
        onError: (context, handler) async {
      // 判断401
      if (context.response?.statusCode == 401) {
        // 1.先判断有没有本地的refreshToken
        String refreshToken = tokenManager.getRefreshToken();
        if (refreshToken.isNotEmpty) {
          try {
            // 尝试换取token
            // 不能使用封装好的dio工具 得完成手写
            await _refresh();
            // 只要走到这里说明换取token成功  重新将这个错误的请求发出去
            // rcp.createSession().get.post.put.fetch
            return handler.resolve(await _dio.fetch(context.requestOptions));
          } catch (e) {
            tokenManager.removeToken(); // 删除本地的token
            emitter.fire(LogoutEvent());
          }

          // onError => pending => rejected
        } else {
          tokenManager.removeToken(); // 删除本地的token
          emitter.fire(LogoutEvent());
        }

        // 跳转到登录页
        // Navigator.pushNamed(context, "/login");

        // 换取token
        // 发布订阅 触发一个事件 别人监听一个事件
        // emitter eventHub
      }
      handler.reject(context);
    }));
  }
  // 换取token
  _refresh() async {
    String refreshToken = tokenManager.getRefreshToken();
    Dio newDio = Dio(); // 换取token必须用新的请求工具
    final res = await newDio.post('${GlobalVariable.BASE_URL}refreshToken',
        options: Options(headers: {"Authorization": 'Bearer $refreshToken'}));
    tokenManager.setToken(res.data["data"]["token"],
        refreshToken: res.data["data"]["refreshToken"]);
  }

  // 工具最终都要通过 dio
  get(String url, {Map<String, dynamic>? params}) {
    return _handleResponse(_dio.get(url, queryParameters: params));
  }

  post(String url, {Map<String, dynamic>? data}) {
    return _handleResponse(_dio.post(url, data: data));
  }

  put(String url, {Map<String, dynamic>? data}) {
    return _handleResponse(_dio.put(url, data: data));
  }

  delete(String url,
      {Map<String, dynamic>? data, Map<String, dynamic>? params}) {
    return _handleResponse(
        _dio.delete(url, data: data, queryParameters: params));
  }

// 因为上传要求formData类型
  upload(String url, {FormData? data}) {
    return _handleResponse(_dio.post(url, data: data));
  }

  _handleResponse(Future<Response<dynamic>> task) async {
    final res = await task;
    // 业务状态码
    if (res.data["code"] == GlobalVariable.SUCCESS_CODE) {
      return res.data["data"]; // fullfiled
    }
    // 提示错误消息
    PromptAction.showError(res.data["message"]);
    // return Promise.reject()
    throw DioException(requestOptions: res.requestOptions); // 抛出异常 rejected状态
  }
}

final dioRequest = DioRequest();

// rcp 中delete要传递请求体参数

// rcp.createSession() instance.delete(url, )
// new rcp.Request("url", {}, null, {})
// instace.fetch(request)
